package com.lottemall.order.service;

import com.lottemall.auth.entity.UserInfo;
import com.lottemall.common.dto.CartDTO;
import com.lottemall.common.enums.ExceptionEnume;
import com.lottemall.common.exception.LtException;
import com.lottemall.common.utils.IdWorker;
import com.lottemall.item.pojo.Sku;
import com.lottemall.order.client.AddressClient;
import com.lottemall.order.client.GoodsClient;
import com.lottemall.order.dto.AddressDTO;
import com.lottemall.order.dto.OrderDTO;
import com.lottemall.order.enums.OrderStatusEnum;
import com.lottemall.order.enums.PayStateEnum;
import com.lottemall.order.interceptors.UserInterceptor;
import com.lottemall.order.mapper.OrderDeatailMapper;
import com.lottemall.order.mapper.OrderMapper;
import com.lottemall.order.mapper.OrderStatusMapper;
import com.lottemall.order.pojo.Order;
import com.lottemall.order.pojo.OrderDetail;
import com.lottemall.order.pojo.OrderStatus;
import com.lottemall.order.utils.PayHelper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.validation.constraints.NotNull;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 订单业务
 */
@Slf4j
@Service
public class OrderService {
    @Autowired
    private OrderMapper orderMapper;
    @Autowired
    private OrderDeatailMapper orderDeatailMapper;
    @Autowired
    private OrderStatusMapper orderStatusMapper;

    //注入支付助手
    @Autowired
    private PayHelper payHelper;

    /**
     * 注入商品接口，调用的是商品微服务中的商品api
     */
    @Autowired
    private GoodsClient goodsClient;

    /**
     * 注入雪花算法对象
     */
    @Autowired
    private IdWorker idWorker;

    /**
     * 创建订单
     *
     * @param orderDTO 封装好的订单传输对象有前台传过来的，只是一些必要标识
     * @return 订单id
     */
    @Transactional
    public Long createOrder(OrderDTO orderDTO) {
        //1.  新增订单
        Order order = new Order();

        //1.1 订单编号，基本信息
        long orderId = idWorker.nextId();
        order.setOrderId(orderId);
        order.setCreateTime(new Date());
        order.setPaymentType(orderDTO.getPaymentType());//支付类型

        //1.2 用户信息
        UserInfo userInfo = UserInterceptor.getUser();
        order.setUserId(userInfo.getId());
        order.setBuyerNick(userInfo.getName());
        order.setBuyerRate(false);//卖家未评价

        //1.3 收获人地址 (人、街道、城市、区、电话、省、邮编)
        //    获取收货人信息（暂时没有做物流地址管理，这里弄得假查询）
        AddressDTO addressDTO = AddressClient.findById(orderDTO.getAddressId());
        order.setReceiver(addressDTO.getName()); //收货人
        order.setReceiverAddress(addressDTO.getAddress());
        order.setReceiverCity(addressDTO.getCity());
        order.setReceiverDistrict(addressDTO.getDistrict());
        order.setReceiverMobile(addressDTO.getPhone());
        order.setReceiverState(addressDTO.getState());
        order.setReceiverZip(addressDTO.getZipCode());

        //1.4 金额
        //得到商品数据集合，里面是商品skuid和该款的数量，为了计算金额   (后面优化这里得到购物车数据承载直接转换成key为skuId,value为该款商品数量)
        Map<Long, Integer> skuIdAndNumMap = orderDTO.getCarts().stream()
                .collect(Collectors.toMap(CartDTO::getSkuId, CartDTO::getNum));
        //到到商品skuId集合
        Set<Long> skuIds = skuIdAndNumMap.keySet();
        //得到sku集合，这里由于参数需要的是List，这里可以这样转
        List<Sku> skuList = goodsClient.querySkuBySpuId(new ArrayList<>(skuIds));
        //定义总金额
        long totalpay = 0L;
        //准备OrderDeatil的集合
        List<OrderDetail> details = new ArrayList<>();
        //遍历sku集合
        for (Sku sku : skuList) {
            //计算商品总价：由于上面数据处理得好，这里可以这样遍历orderDTO.getCarts()中，从而计算用户此次订单需要支付的总金额
            totalpay += sku.getPrice() * skuIdAndNumMap.get(sku.getId());
            //封装orderDetail
            OrderDetail orderDetail = new OrderDetail();
            //填充数据
            //取出sku商品的图片，由于图片不止一张，这样可以取出第一张图片
            orderDetail.setImage(StringUtils.substringBefore(sku.getImages(), ","));
            orderDetail.setNum(skuIdAndNumMap.get(sku.getId()));
            orderDetail.setOrderId(orderId);
            orderDetail.setOwnSpec(sku.getOwnSpec());
            orderDetail.setPrice(sku.getPrice());
            orderDetail.setSkuId(sku.getId());
            orderDetail.setTitle(sku.getTitle());
            //扔进订单详情集合
            details.add(orderDetail);
        }
        //设置此订单的总金额
        order.setTotalPay(totalpay);
        //设置实付金额（总金额 + 邮费 - 优惠金额）
        order.setActualPay(totalpay + order.getPostFee() - 0);

        //1.5 order写入数据库(insertSelective有选择新的添加，因为我们Order中有的数据没有设置，需要数据库的默认值)
        int count = orderMapper.insertSelective(order);
        if (count != 1) {
            log.error("[创建订单]创建订单失败，orderId:{}", orderId);
            throw new LtException(ExceptionEnume.CREATE_ORDER_ERROR);
        }

        //2  新增订单详情
        count = orderDeatailMapper.insertList(details);
        if (count != details.size()) {
            log.error("[创建订单]创建订单详情失败，orderId:{}", orderId);
            throw new LtException(ExceptionEnume.CREATE_ORDER_ERROR);
        }
        //3  新增订单状态
        OrderStatus orderStatus = new OrderStatus();
        orderStatus.setCreateTime(order.getCreateTime());
        orderStatus.setOrderId(orderId);
        orderStatus.setStatus(OrderStatusEnum.UN_PAY.value());
        count = orderStatusMapper.insertSelective(orderStatus);
        if (count != 1) {
            log.error("[创建订单]创建订单失败，orderId:{}", orderId);
            throw new LtException(ExceptionEnume.CREATE_ORDER_ERROR);
        }

        //4  更新库存
        List<CartDTO> cartDTOList = orderDTO.getCarts();
        goodsClient.decreaseStock(cartDTOList);
        return orderId;
    }

    /**
     * 查询订单信息
     *
     * @param id 订单id
     * @return
     */
    public Order queryOrderById(Long id) {
        //查询订单
        Order order = orderMapper.selectByPrimaryKey(id);
        if (order == null) {
            throw new LtException(ExceptionEnume.ORDER_NOT_FOUND);
        }
        //查询订单详情
        OrderDetail orderDetail = new OrderDetail();
        orderDetail.setOrderId(order.getOrderId());
        List<OrderDetail> orderDetailList = orderDeatailMapper.select(orderDetail);
        if (CollectionUtils.isEmpty(orderDetailList)) {
            throw new LtException(ExceptionEnume.ORDER_DETAIL_NOT_FOUND);
        }
        order.setOrderDetails(orderDetailList);
        //查询订单状态
        OrderStatus orderStatus = orderStatusMapper.selectByPrimaryKey(order.getOrderId());
        if (orderStatus == null) {
            throw new LtException(ExceptionEnume.ORDER_STATUS_NOT_FOUND);
        }
        order.setOrderStatus(orderStatus);
        return order;
    }

    /**
     * 创建支付链接
     *
     * @param orderId
     * @return
     */
    public String createPayUrl(Long orderId) {
        //查询订单
        Order order = queryOrderById(orderId);
        //首先判断下订单的状态，如果已支付就不需要下面操作
        Integer status = order.getOrderStatus().getStatus();
        if (status != OrderStatusEnum.UN_PAY.value()) {
            //订单状态不等于未付款
            throw new LtException(ExceptionEnume.ORDER_STATUS_ERROR);
        }
        //支付金额
        Long actualPay = order.getActualPay();
        //开发阶段将支付金额统一设置为一分钱
        actualPay = 1L;

        //商品描述
        OrderDetail orderDetail = order.getOrderDetails().get(0);
        String desc = orderDetail.getTitle();//得到商品描述
        return payHelper.createPayUrl(orderId, desc, actualPay);
    }

    /**
     * 给微信支付系统进行回调，
     *
     * @param result
     */
    public void handleNotify(Map<String, String> result) {
        //数据校验
        if (!payHelper.isSuccess(result)) {
            throw new LtException(ExceptionEnume.WX_PAY_NOTIFY_SERVICE_ERROR);
        }
        //校验签名
        if (!payHelper.isSignatureValid(result)) {
            throw new LtException(ExceptionEnume.WX_PAY_SIGN_INVALID);
        }
        //校验金额和订单编号
        //得到结果中的金额
        String totalFeeStr = result.get("total_fee");
        //得到结果中的订单编号
        String tradeNo = result.get("out_trade_no");
        if (StringUtils.isEmpty(totalFeeStr) || StringUtils.isEmpty(tradeNo)) {
            throw new LtException(ExceptionEnume.INVALID_ORDER_PARAM);
        }
        //金额不为空，我们就转化成Long
        Long totalFee = Long.valueOf(totalFeeStr);

        Long orderId = Long.valueOf(tradeNo);
        Order order = orderMapper.selectByPrimaryKey(orderId);
        //获取真实存储的数据中的订单金额
        if (totalFee !=/*order.getActualPay()*/1) { //如果微信支付系统返回的金额不等于实际订单记录中的金额，就错误（这里由于开发测试我们弄得都是1）
            throw new LtException(ExceptionEnume.INVALID_ORDER_PARAM);
        }

        //以上数据都合法，就可以进行以下了
        //更新订单状态
        OrderStatus orderStatus = new OrderStatus();
        orderStatus.setStatus(OrderStatusEnum.PAYED.value());
        orderStatus.setOrderId(orderId);
        orderStatus.setPaymentTime(new Date());
        int count = orderStatusMapper.updateByPrimaryKeySelective(orderStatus);
        if (count != 1) {
            throw new LtException(ExceptionEnume.UPDATE_ORDER_STATUS_ERROR);
        }
        log.info("[订单回调]，订单支付成功，订单编号：{}", orderId);
    }

    /**
     * 查询订单支付状态（用于前台用户扫描支付二维码的定时查询判断用户是否支付成功进行跳转）
     *
     * @param orderId
     * @return
     */
    public PayStateEnum queryOrderState(Long orderId) {
        //查询订单状态
        OrderStatus orderStatus = orderStatusMapper.selectByPrimaryKey(orderId);
        Integer status = orderStatus.getStatus();
        //判断是否支付
        if (status != OrderStatusEnum.UN_PAY.value()) {
            //如果已支付，就真的是已支付了
            return PayStateEnum.SUCCESS;
        }
        //如果是未支付，但其实不一定是未支付,因为很有可能是用户支付了，微信支付系统回调我们太慢了，状态来不及更新，所以必须去微信查询支付状态（这个需要注意的）
        return payHelper.queryPayState(orderId);
    }
}
